import { action, toJS } from 'mobx';
import moment from 'moment';
import i18n from 'i18n-js';
import global from '@/utils/global';
import SDK from '@/utils/SDK';
import { deviceIsBleConnect, getDeviceId } from '@/utils';
import GStatistics, { GStatisticsEvent } from '@/utils/GStatistics';
import ServiceInfoManager from '@/utils/ServiceInfoManager';
import ProductConfig, {
  getItemForPk,
  getCmdLimitProduct,
  isThirdCloud,
  IProduct,
  ICmdLimitConfig,
} from '@/config/product';
import Toast from '@/utils/Toast';
import DeviceList from './deviceList/index';
import Homes from './homes';
import DeviceData from './deviceData';

import { init, write, getDeviceList, writeBigData } from '../services/gizwitsSdk';

// sdk可能有包含微信结果的IWechatResult，需要统一判定
function isResSuccess(res) {
  console.log('isResSuccess', res);
  return !!(res && ((res.errCode !== undefined && res.errCode == 0) || res.success));
}

function limitUpdateList({ list, max, item }: { list: any[]; max: number; item: any }) {
  let newList = [...list];
  if (list.length >= max) {
    newList = newList.slice(list.length - max + 1, list.length);
  }
  newList.push(item);
  return newList;
}

function updateTimeStampList({
  list,
  max,
  curTimestamp,
  limitMinTime,
}: {
  list: number[];
  max: number;
  curTimestamp: number;
  limitMinTime: number;
}) {
  if (list.length > 0) {
    const firstItem = list[0];
    // 每次推一个元素进来，都检查下是不是距离第一个元素太远了，是的话，就剔除掉第一个元素
    if (curTimestamp - firstItem > limitMinTime) {
      console.log('剔除第一个元素');
      list.splice(0, 1);
    }
  }
  return limitUpdateList({ list, max, item: curTimestamp });
}

interface ICmdCacheInfo {
  lastSendTimestamp: number; // 设备最后一次下发时间戳
  count: number; // 记录单位时间内控制的次数
  limitConfig?: ICmdLimitConfig; // 限制配置
  timer?: any; // 用于存储计时器
  inLimit: boolean; // 标识是不是已经触发了限制
  cmdTimeList: number[]; // 指令时间戳数组
}

interface ICmdMap {
  [key: string]: ICmdCacheInfo;
}

interface IConfigCmd {
  [key: string]: ICmdLimitConfig;
}

class GizwitsSdk {
  cmdMap: ICmdMap = {};

  configMap: IConfigCmd = {};

  @action
  async init(payload: { cloudServiceInfo: IServiceInfo }) {
    const data = await init({
      cloudServiceInfo: payload.cloudServiceInfo,
    });
    return data;
  }

  @action
  async initWithCurrentLanguage() {
    const serviceInfo = await ServiceInfoManager.getServiceInfo();
    const data = await init({
      cloudServiceInfo: serviceInfo,
    });
    if (data.success && global.token) {
      await getDeviceList();
    }
    return data;
  }

  // 增加配置
  async addProduct(data: IProduct) {
    await ProductConfig.addProduct(data);
    // 重新启动sdk
    await this.initWithCurrentLanguage();
  }

  @action
  async sendCmd(payload: { data: { [key: string]: any }; device: IDevice }) {
    const { data, device } = payload;
    const jsDevice = toJS(device);
    let deviceList: IDevice[] = [];
    if (jsDevice.groupID) {
      // 分组也不监听
      // 如果是分组设备，需要把整个分组都放进去
      const deviceListState = toJS(DeviceList.data);
      const homesState = toJS(Homes.data);
      let group: IGroup | undefined;
      homesState.find(
        // eslint-disable-next-line consistent-return
        home =>
          (home.rooms || []).findIndex(room => {
            group = room.groups.find(item => item.id === jsDevice.groupID);
            if (group) {
              return true;
            }
          }) > -1
      );

      if (group) {
        deviceList = deviceListState.filter(item => (group as IGroup).snos.findIndex(sno => sno === item.sno) > -1);
      }
    } else {
      deviceList.push(jsDevice);
    }

    /**
     * 普通的组
     * 直接遍历发过去
     */
    // eslint-disable-next-line no-restricted-syntax
    for (const item of deviceList) {
      // 把数据更新到deviceData modal
      DeviceData.setDeviceDataInAdvance({ device: item, data });
      const config = getItemForPk(device.productKey);
      if (isThirdCloud(config)) {
        // 先不处理
      } else {
        console.log('Device write');
        write({ device: item, data }).then(res => {
          console.log('Device write res', res);
          if (deviceIsBleConnect(item)) {
            const bleEvent = new GStatisticsEvent.BleDeviceControlEvent({
              extra: {
                product_key: item.productKey,
                send_cmd_success: isResSuccess(res),
                send_cmd_result: JSON.stringify(res),
              },
            });
            GStatistics.postCalculateEvent(bleEvent);
          }
        });
      }
    }
  }

  @action
  async sendBroadCastBigData(payload: { data: number[]; device: IDevice }) {
    const { data, device } = payload;
    console.warn('Device write boardcast big data');
    const jsDevice = toJS(device);
    return await writeBigData({ device: jsDevice, data });
  }

  @action
  async sendCmdHaveRes(payload: { data: { [key: string]: any }; device: IDevice }) {
    const { data, device } = payload;
    DeviceData.setDeviceDataInAdvance({ device, data });
    console.log('Device write');
    const res = await write({ device, data });
    const success = isResSuccess(res);
    if (deviceIsBleConnect(device)) {
      const bleEvent = new GStatisticsEvent.BleDeviceControlEvent({
        extra: {
          product_key: device.productKey,
          send_cmd_success: success,
          send_cmd_result: JSON.stringify(res),
        },
      });
      GStatistics.postCalculateEvent(bleEvent);
    }
    return { ...res, success };
  }

  // 获取设备下发指令的限制配置
  getDeivceSendDataLimitConfig(device: IDevice) {
    let limitConfig = this.configMap[device.productKey];
    if (!limitConfig) {
      limitConfig = getCmdLimitProduct(device.productKey);
      if (limitConfig) {
        this.configMap[device.productKey] = limitConfig;
      }
    }
    return limitConfig;
    // return {
    //   limitMinTime: 180000,
    //   limitUnitTime: 250,
    //   limitMinCount: 720,
    //   lockTime: 2000,
    //   unlockTime: 10000,
    // };
  }

  @action
  async sendCmdLimit(payload: { data: { [key: string]: any }; device: IDevice; callback?: (res: IResult) => void }) {
    console.log('sendCmdLimit', this.cmdMap);
    const { device, callback } = payload;
    // 先查询这台设备的指令队列，有队列的话，按队列记录的情况开始判断
    const deviceId = getDeviceId(device);
    let deviceCmdInfo = this.cmdMap[deviceId];
    let limitConfig;
    if (deviceCmdInfo && deviceCmdInfo.limitConfig) {
      limitConfig = deviceCmdInfo.limitConfig;
    } else {
      limitConfig = this.getDeivceSendDataLimitConfig(device);
      if (limitConfig) {
        deviceCmdInfo = {
          lastSendTimestamp: 0,
          count: 0,
          limitConfig,
          timer: undefined,
          inLimit: false,
          cmdTimeList: [],
        };
      }
    }
    // 有限制规则的，才开始判断需不需要限制下发
    if (limitConfig) {
      console.log('有限制规则的，需要计算');
      const { lastSendTimestamp, count, timer, inLimit, cmdTimeList } = deviceCmdInfo;
      const { limitMinTime, limitUnitTime, limitMinCount, lockTime, unlockTime } = limitConfig;
      const curTimestamp = moment().valueOf();

      let newTimer = timer;
      if (inLimit) {
        // 已经是触发了限制的情况
        if (curTimestamp - lastSendTimestamp <= lockTime) {
          // 在限制时间内，不可发送，并提示
          console.log('在限制时间内，不可发送');
          Toast.info(i18n.t('OPERATION_TOO_QIUCK'));
          if (callback) {
            callback({ success: false });
          }
          return { success: false };
        }
      } else if (curTimestamp - lastSendTimestamp <= limitUnitTime) {
        // 这里不需要提示
        console.log('在前期限制时间内，不可发送');
        if (callback) {
          callback({ success: false });
        }
        return { success: false };
      }

      const newCount = count + 1;
      let newInLimit = inLimit;
      let newCmdTimeList = cmdTimeList || [];
      // 触发了限制的话，发送的指令就不需要算在这里面了
      if (!inLimit) {
        newCmdTimeList = updateTimeStampList({ list: newCmdTimeList, max: limitMinCount, curTimestamp, limitMinTime });
      }
      const startTimestamp = newCmdTimeList[0];
      console.log('tt', !newInLimit, curTimestamp - startTimestamp, limitMinTime, newCount);
      if (!newInLimit && curTimestamp - startTimestamp <= limitMinTime && newCount >= limitMinCount) {
        // 在最小触发持续时间，到达最小限制次数，开启限制
        console.log('触发限制了，开始计时', curTimestamp);
        newInLimit = true;
        if (newTimer) {
          clearTimeout(newTimer);
        }
        newTimer = setTimeout(() => {
          console.log('限制时间到了，解除限制', moment().valueOf());
          this.unlockDeviceCmdSend(device);
        }, unlockTime);
      }

      deviceCmdInfo = {
        ...deviceCmdInfo,
        count: newCount,
        lastSendTimestamp: curTimestamp,
        timer: newTimer,
        inLimit: newInLimit,
        cmdTimeList: newCmdTimeList,
      };
      this.cmdMap[deviceId] = deviceCmdInfo;
    }
    console.log('发送指令', this.cmdMap);
    this.sendCmdHaveRes(payload).then(res => {
      if (callback) {
        callback(res);
      }
    });
    return { success: true };
  }

  unlockDeviceCmdSend(device: IDevice) {
    const deviceId = getDeviceId(device);
    const deviceCmdInfo = this.cmdMap[deviceId];
    if (deviceCmdInfo && deviceCmdInfo.timer) {
      clearTimeout(deviceCmdInfo.timer);
      delete this.cmdMap[deviceId];
    }
  }

  @action
  async getDeviceStatus({ device, attrs }: { device: IDevice; attrs?: string[] }) {
    const data = await SDK.getDeviceStatus({ device, attrs });
    return data;
  }

  sendTimeCorrectCmd(device: IDevice) {
    const now = moment();
    // eslint-disable-next-line camelcase
    const cur_timestamp = now.unix();
    // eslint-disable-next-line camelcase
    const cmd: any = { cur_timestamp };
    const zoneStr = now.format('ZZ');
    console.log('now', cur_timestamp, zoneStr);
    if (zoneStr && zoneStr.length > 2) {
      // 时区格式是 +0800这样的，只拿前3个字符来处理
      const tmpStr = zoneStr.substring(0, 3);
      console.log(parseInt(tmpStr, 10));
      cmd.cur_timezone = parseInt(tmpStr, 10) + 12; // 加12，确保传给设备是1-24
    }
    console.log(cmd);
    this.sendCmd({ device, data: cmd });
  }
}

export default new GizwitsSdk();
